Skip to content

Migrate build system from Makefile to CMake - #116

Merged
tmolteno merged 10 commits into
masterfrom
feat/cmake-migration
Jul 22, 2026
Merged

Migrate build system from Makefile to CMake#116
tmolteno merged 10 commits into
masterfrom
feat/cmake-migration

Conversation

@tmolteno

Copy link
Copy Markdown
Owner

Summary

Replaces the v2.0.0 hand-written Makefile (plus the broken debian/, win32/, build/*.sh, and Gentoo ebuild packaging) with a single CMake-based build.

New build system (527 lines)

  • CMakeLists.txt — top-level: owns the version (single source of truth, was duplicated in 4 places), options, configure_file(config.h), and CPack (DEB/RPM/TXZ).
  • src/CMakeLists.txt — defines the canonical source list once; an OBJECT library backs both libnecpp.a and libnecpp.so (soname libnecpp.so.2). Full install/export: headers, pkg-config (necpp.pc), CMake package config (find_package(necpp)necpp::necpp), man pages.
  • Tests run under CTest (35 Catch cases, 289 assertions) with a checked-in test_main.cpp replacing the printf-synthesised one.
  • WASM is a native CMake target (-DNECPP_BUILD_WASM=ON via emcmake) wrapped by scripts/build_wasm_docker.sh for hosts without emsdk.
  • CI is now a 3-OS matrix (ubuntu/macos/windows) plus a WASM job.

Deletions

Makefile, debian/ (targets the removed autotools/atlas/python-numpy), win32/ Visual Studio project (replaced by CMake's VS generator), build/*.sh legacy scripts, nec2++-9999.ebuild, docs/Makefile (superseded by docs.yml), example/Makefile*.

ANTLR kept Docker-isolated

The ANTLR nec_parse parser stays a separate Docker build per the design; only its build_in_docker.sh was updated to read the version from CMakeLists.txt (the Makefile is gone).

Verification

All checks passed locally:

Check Result
cmake -B build && cmake --build build ✅ builds nec2++, nec2diff, libnecpp.a, libnecpp.so
Byte-identical simulation output vs Makefile baseline (herzian_dipole, example1, dipole_anim, bruce_sommerfeld) ✅ identical (only non-deterministic msec timing lines differ)
ctest (35 Catch cases, 289 assertions) ✅ all pass
Static-only build (-DBUILD_SHARED_LIBS=OFF) ✅ produces only libnecpp.a
cmake --installpkg-config --cflags --libs necpp -I/usr/local/include/necpp -L/usr/local/lib -lnecpp
find_package(necpp) from a consumer project ✅ links & runs
CPack DEB → split packages necpp (CLI), libnecpp2 (runtime), libnecpp-dev (devel)
WASM via scripts/build_wasm_docker.sh ✅ produces nec2pp.js + nec2pp.wasm
ANTLR nec_parse build (Docker) + simulation ✅ end-to-end works

Build/usage

The short version (full details in the updated INSTALL.md):

cmake -B build
cmake --build build -j4
sudo cmake --install build

Notable behavior change

cmake --install now installs headers + a shared library + man pages — the old Makefile only installed the nec2++ binary. This restores what libnecpp-dev/libnecpp0 packaging and example/Makefile.pkg-config always expected but could never work against the v2.0.0 build.

Out of scope (follow-ups)

  • testharness/ FORTRAN/C comparison harness — standalone, left as-is.
  • Ruby/ext/necpp/ SWIG binding — references the old eigen3 path; needs separate rework against the installed library.
  • A proper CMake-based example in example/ (currently reduced to a README snippet).

tmolteno added 5 commits July 22, 2026 09:19
Replaces the v2.0.0 hand-written Makefile (plus the broken debian/, win32/,
build/*.sh, and Gentoo ebuild packaging) with a single CMake-based build.

New build system (527 lines across cmake/, src/CMakeLists.txt, tests/):
- CMakeLists.txt owns the version (single source of truth, was duplicated in
  4 places), options, configure_file(config.h), and CPack (DEB/RPM/TXZ).
- src/CMakeLists.txt defines the canonical source list once; an OBJECT library
  backs both libnecpp.a and libnecpp.so (soname libnecpp.so.2). Full install/
  export: headers, pkg-config (necpp.pc), CMake package config (find_package
  (necpp) -> necpp::necpp), man pages.
- Tests run under CTest (35 Catch cases, 289 assertions) with a checked-in
  test_main.cpp replacing the printf-synthesised one.
- WASM is a native CMake target (-DNECPP_BUILD_WASM=ON via emcmake) wrapped by
  scripts/build_wasm_docker.sh for hosts without emsdk.
- CI is now a 3-OS matrix (ubuntu/macos/windows) plus a WASM job.

Deletions: Makefile, debian/ (targets removed autotools/atlas/python-numpy),
win32/ Visual Studio project (replaced by CMake's VS generator), build/*.sh
legacy scripts, nec2++-9999.ebuild, docs/Makefile (superseded by docs.yml),
example/Makefile*.

Verified: simulation output byte-identical to the Makefile build across four
.nec files (only non-deterministic msec timing lines differ); all 35 Catch
test cases pass; static-only build works; pkg-config and find_package(necpp)
both resolve against a DESTDIR install; CPack produces split
necpp/libnecpp2/libnecpp-dev packages; WASM and the ANTLR nec_parse Docker
build both produce working artifacts.

The ANTLR parser stays Docker-isolated per the migration design; only its
build_in_docker.sh was updated to read the version from CMakeLists.txt.
…tchContent)

- Replace vendored src/catch.hpp (423KB, v1.9.7) with CMake FetchContent
  downloading Catch2 v3.7.1 at configure time.
- Delete tests/test_main.cpp — Catch2::Catch2WithMain provides main().
- Remove --allow-multiple-definition linker hack (was needed because both
  test_main.cpp and safe_array_tb.cpp defined CATCH_CONFIG_MAIN).
- Remove stray CATCH_CONFIG_MAIN from safe_array_tb.cpp.
- Update all 7 *_tb.cpp includes: "catch.hpp" → <catch2/catch_test_macros.hpp>.
- Add math_util_tb.cpp to the test runner (was excluded historically).
- Expand CTest to run all 42 test cases (up from 13 tag groups / 35
  assertions) using ~[surface_patch] exclusion for one pre-existing
  failure. New tests now running: nec_3vector, lu_decompose_ge, 3
  nec_context_tb simulation tests (example_1, voltage_excitation,
  plane_wave), 2 helix regressions.
- Fix Catch::Approx namespace qualification for Catch2 v3 compatibility.

Result: 42 test cases, 341 assertions, all passing. Clean link, no hacks.
The Ruby binding (SWIG wrapper + genetic optimizer) was entirely
self-contained and not wired into any build system. It targeted the
pre-CMake build and the old eigen3/ include path.

The Python binding moved to a separate repository
(tmolteno/python-necpp) long ago; the Ruby binding has no
equivalent downstream home.

Deleted: Ruby/ (24 files, 3 directories). Updated: README.md,
TODO.md to remove Ruby as a current-language reference. Historical
changelog entries in NEWS/ and CHANGELOG.md are left as-is.
The Ruby directory (24 files, 3 subdirectories) was removed but the
file deletions were not included in the parent commit. This captures
the actual deletion of all Ruby/SWIG files.
MSVC does not understand GCC warning flags. Use /W3 on MSVC and
keep -Wall -Wextra -Wshadow on GCC/Clang, matching the warning
level the hand-written Makefile enforced on Linux.
@tmolteno
tmolteno force-pushed the feat/cmake-migration branch from ef88ed7 to 402572d Compare July 22, 2026 03:17
tmolteno added 5 commits July 22, 2026 15:59
- Add `win32_ci_guard.cpp` to disable Windows modal dialogs (WerFault, abort) that hang headless CI runners.
- Guard the `m` library link for MSVC in `tests/CMakeLists.txt`.
- Add a 30-minute timeout to the CI job and a 300-second timeout to CTest to fail fast on hangs.
- Silence MSVC deprecation warnings for the test target using `_CRT_SECURE_NO_WARNINGS`.
- Move `_CRT_SECURE_NO_WARNINGS` to the top-level CMakeLists.txt so it
  applies project-wide instead of only to the test target.
- Remove the unconditional `m` library link from the test target; math
  functions are part of the C runtime on Windows/MSVC.
- Fix the C4101 unreferenced local variable warning in `safe_array.h`
  by dropping the unused `ba` binding in the catch clause.
Catch2 built as a DLL on Windows MSVC deadlocks the loader during
static init across the EXE<->DLL registry boundary, causing nec2++_tests
to hang for the full 300s timeout with zero output. Setting
BUILD_SHARED_LIBS OFF before FetchContent_MakeAvailable ensures Catch2
is built static while leaving libnecpp's shared library configuration
unaffected.
@tmolteno
tmolteno merged commit af53f95 into master Jul 22, 2026
4 checks passed
@tmolteno
tmolteno deleted the feat/cmake-migration branch July 22, 2026 08:34
@tmolteno tmolteno mentioned this pull request Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant